#include "Geometry.h"

#include "bitstd.h"
#include "bitdev.h"

/////////////////////////////////////////////////////////////////
T3DPoint :: T3DPoint( const T3DPoint& aItem )
{
   operator = ( aItem );
}

T3DPoint& T3DPoint :: operator = ( const T3DPoint& aPoint )
{
   iX = aPoint.iX;
   iY = aPoint.iY;
   iZ = aPoint.iZ;
   return *this;
}       


/////////////////////////////////////////////////////////////////
TDouble3DPoint :: TDouble3DPoint( TInt aX, TInt aY, TInt aZ )
{
   iOriginal.iX = aX;
   iOriginal.iY = aY;
   iOriginal.iZ = aZ;
	
   iCurrent.iX = 0;
   iCurrent.iY = 0;
   iCurrent.iZ = 0;
}

TDouble3DPoint :: TDouble3DPoint( const TDouble3DPoint& aItem )
{
   operator =( aItem );
}
	   
TDouble3DPoint& TDouble3DPoint :: operator = ( const TDouble3DPoint& aPoint )
{
   iOriginal = aPoint.iOriginal;
   iCurrent  = aPoint.iCurrent;
   return *this;
}       


/////////////////////////////////////////////////////////////////
CTransformMatrix :: ~CTransformMatrix()
{
   delete iLine1;
   delete iLine2;
   delete iLine3;
}

CTransformMatrix* CTransformMatrix :: NewL()
{
   CTransformMatrix* self = new (ELeave) CTransformMatrix();
   CleanupStack::PushL( self );
   self->ConstructL();
   CleanupStack :: Pop( self );
   return self;    	
}

// ��筥��� ������ ������ �� ��������� 㣫��
void CTransformMatrix :: Refine( TReal anAngleXoffs, TReal anAngleYoffs, TReal anAngleZoffs )
{
   angleX += anAngleXoffs;
   angleY += anAngleYoffs;
   angleZ += anAngleZoffs;
	
   TReal sinX, sinY, sinZ,
         cosX, cosY, cosZ;

   Math :: Sin( sinX, angleX );
   Math :: Sin( sinY, angleY );
   Math :: Sin( sinZ, angleZ );

   Math :: Cos( cosX, angleX );
   Math :: Cos( cosY, angleY );
   Math :: Cos( cosZ, angleZ );	
	
   (*iLine1)[0] = cosY * cosZ;
   (*iLine1)[1] = sinX * sinY * cosZ + sinZ * cosX;
   (*iLine1)[2] = sinX * sinZ - cosX * sinY * cosZ;
	
   (*iLine2)[0] = -sinZ * cosY;
   (*iLine2)[1] = cosX * cosZ - sinX * sinY * sinZ;
   (*iLine2)[2] = sinX * cosZ + cosX * sinY * sinZ;
	
   (*iLine3)[0] = sinY;
   (*iLine3)[1] = -sinX * cosY;
   (*iLine3)[2] = cosX * cosY;	
}	

void CTransformMatrix :: Reset() 
{ 
   angleX = angleY = angleZ = 0; 
}


void CTransformMatrix :: ConstructL()
{	
   iLine1 = InitLineL();
   iLine2 = InitLineL();
   iLine3 = InitLineL();
}

// ���樠������ ��ப� ������
CArrayFixFlat<TReal>* CTransformMatrix :: InitLineL()
{
   CArrayFixFlat<TReal>* result = new (ELeave) CArrayFixFlat<TReal>( 3 );
   result->AppendL( 0 );
   result->AppendL( 0 );
   result->AppendL( 0 );
   return result;
}

// 㬭������ ����� �� ������
void CTransformMatrix :: Multiply( T3DPoint& aMultiplier, T3DPoint& aResult )
{
   aResult.iX = aMultiplier.iX * (*iLine1)[ 0 ] + 
           	aMultiplier.iY * (*iLine1)[ 1 ] +     	
	        aMultiplier.iZ * (*iLine1)[ 2 ];
        
   aResult.iY = aMultiplier.iX * (*iLine2)[ 0 ] + 
                aMultiplier.iY * (*iLine2)[ 1 ] +     	
                aMultiplier.iZ * (*iLine2)[ 2 ];
         
   aResult.iZ = aMultiplier.iX * (*iLine3)[ 0 ] + 
                aMultiplier.iY * (*iLine3)[ 1 ] +     	
                aMultiplier.iZ * (*iLine3)[ 2 ];	
}


/////////////////////////////////////////////////////////////////
TParallelepipedPoly :: TParallelepipedPoly( const TParallelepipedPoly& aPoly )
{
   operator = ( aPoly );
}
	   
TParallelepipedPoly& TParallelepipedPoly :: operator = ( const TParallelepipedPoly& aPoly )
{
   iVisible = aPoly.iVisible;
   iColor   = aPoly.iColor;
           
   iPoint1 = aPoly.iPoint1;
   iPoint2 = aPoly.iPoint2;
   iPoint3 = aPoly.iPoint3;
   iPoint4 = aPoly.iPoint4;
          
   return *this;
}       
    	    	
// ��� ���ᮢ�� �������� � ������� �㭪樨 DrawPloy �� ��� 
// ���設� ����室��� �������� � ���ᨢ
void TParallelepipedPoly :: SetArray( TPoint* anArray )
{
   anArray[0] = iPoint1;
   anArray[1] = iPoint2;
   anArray[2] = iPoint3;
   anArray[3] = iPoint4;
}

// ��⠭���� ���祭�� ����� �� ���設       
void TParallelepipedPoly :: SetPoint( TInt aPointIdx, TInt aX, TInt aY )
{
   switch( aPointIdx )
   {
      case 0:
         iPoint1.iX = aX;
         iPoint1.iY = aY;
         break;
        	  
      case 1:
         iPoint2.iX = aX;
         iPoint2.iY = aY;
         break;
        	  
      case 2:
         iPoint3.iX = aX;
         iPoint3.iY = aY;        	  
         break;
        	  
      default:
         iPoint4.iX = aX;
         iPoint4.iY = aY;        	  
         break;
   }
}


/////////////////////////////////////////////////////////////////
CParallelepiped :: CParallelepiped( TReal aMultiplier, TDisplayMode aMode )
{		
   // �ࠧ� ��᫥ ᮧ����� ⥪�騬 �������஬ ���� Dx
   // ���饭�� 㣫�� ������ �� �ᥬ ���ࠢ����� ࠢ�� 0
   iDCurrent = &iDx; 
   iDx = iDy = iDz = 0;
   iMultiplier = aMultiplier;
   iMode = aMode;
}


void CParallelepiped :: ConstructL()
{	   
   // ��ࠫ��������� ᮤ�ন� 8 ���設
   iPoints = new (ELeave) CArrayFixFlat<TDouble3DPoint>( 8 );
   
   // � 6 �࠭�� - ��� ������ �������� ᮡ�⢥��� 梥�
   iPolies = new CArrayFixFlat<TParallelepipedPoly>( 6 );
   iPolies->AppendL( TParallelepipedPoly( KRgbRed ) );
   iPolies->AppendL( TParallelepipedPoly( KRgbGreen ) );
   iPolies->AppendL( TParallelepipedPoly( KRgbBlue ) );
   iPolies->AppendL( TParallelepipedPoly( KRgbYellow ) );
   iPolies->AppendL( TParallelepipedPoly( KRgbCyan ) );
   iPolies->AppendL( TParallelepipedPoly( KRgbGray ) );

   // �ᯮ����⥫�� ���ᨢ ��� ���ᮢ�� ��������
   iPoly = new (ELeave) TPoint[ 4 ];

   iGaugePoly = new (ELeave) TPoint[ 3 ];

   // ����� ������
   iMatrix = CTransformMatrix :: NewL();      
}


CParallelepiped :: ~CParallelepiped()
{
   delete iPoints;
   iPoints = NULL;	
	
   delete iPolies;
   iPolies = NULL;
	
   delete [] iPoly;
   iPoly = NULL;
	
   delete [] iGaugePoly;
   iGaugePoly = NULL;
   
   delete iMatrix;
   iMatrix = NULL;
			
   delete iOffScreenBitmapGc;
   iOffScreenBitmapGc = NULL;

   delete iOffScreenBitmapDevice;
   iOffScreenBitmapDevice = NULL;

   delete iOffScreenBitmap;
   iOffScreenBitmap = NULL;		
}

// ��⠭���� ���न��� �������� ���設� ��������� ��������
void CParallelepiped :: SetPolyPoint( TInt aPolyNo, TInt aPointNo, TInt aValueX, TInt aValueY )
{
   (*iPolies)[aPolyNo].SetPoint( aPointNo, aValueX, aValueY );
}

// ��⠭���� ��砫��� ���祭�� ���設 ��ࠫ����������
// ���न���� �����뢠���� � ����ᨬ��� �� ࠧ��஢ �쫠�� ���ᮢ��
// �⮡� �� ��饭�� �� ��� �� �।���
void CParallelepiped :: SetInitPoints( const TRect& aRect, const TPoint& aPoint )
{
   iRect  = aRect;
   iPoint = aPoint;

   TInt x = aRect.Width();
   if( aRect.Height() < x )
	x = aRect.Height();
	   
   TInt xOffs = x / 4,
        yOffs = x / 4,
        zOffs = x / 3;
           
   iPoints->Reset();
   iPoints->AppendL( TDouble3DPoint(  xOffs,  yOffs, -zOffs) );
   iPoints->AppendL( TDouble3DPoint(  xOffs, -yOffs, -zOffs) );
   iPoints->AppendL( TDouble3DPoint( -xOffs, -yOffs, -zOffs) );
   iPoints->AppendL( TDouble3DPoint( -xOffs,  yOffs, -zOffs) );
   iPoints->AppendL( TDouble3DPoint(  xOffs,  yOffs,  zOffs) );
   iPoints->AppendL( TDouble3DPoint(  xOffs, -yOffs,  zOffs) );
   iPoints->AppendL( TDouble3DPoint( -xOffs, -yOffs,  zOffs) );
   iPoints->AppendL( TDouble3DPoint( -xOffs,  yOffs,  zOffs) );	   
}

// ��⠭���� 䮪��: �᫨ �� 0 - ����� ��।�� ����� ⥪�饣�
// ��⨢���� ��������
void CParallelepiped :: SetFocused( TInt aFocused ) 
{ 
   if( aFocused )
   {
      iFocused = ETrue; 
      SetGauge( aFocused );
   }
   else
      iFocused = EFalse; 
}

// ��⠭���� ��⨢���� ��������
void CParallelepiped :: SetGauge( TInt aGauge ) 
{ 
   switch( aGauge ) 
   {
      case 1:
        iDCurrent = &iDx;
        break;

      case 2:
        iDCurrent = &iDy;
        break;

      case 3:
        iDCurrent = &iDz;
        break;

      default:
        break;
   }
}

// ��⠭���� ���祭�� ⥪�饣� ��⨢���� ��������
void CParallelepiped :: SetCurrentGaugeValue( TInt aValue ) 
{ 
   *iDCurrent = aValue; 
}

// ����� ����� ���न��� ���設
void CParallelepiped :: Calc( )
{
   // ���� ����� ���祭�� ������ ������
   iMatrix->Refine( iMultiplier * iDx, iMultiplier * iDy, iMultiplier * iDz );

   // ���� ����� ���न��� ���設 ��ࠫ����������
   TInt maxZ = 0;
   for( TInt i = 0; i < 8; i++ )
   {
      iMatrix->Multiply( (*iPoints)[i].iOriginal, (*iPoints)[i].iCurrent );    	
      if( (*iPoints)[i].iCurrent.iZ > (*iPoints)[maxZ].iCurrent.iZ )
         maxZ = i;
   }
    
   // ��⠭���� ����� ���祭�� ��� ���������
   // � ��⮬ ᬥ饭�� ��� ���ᮢ�� �� 業��� ������
   TInt xOffs = iRect.Width() / 2,
        yOffs = iRect.Height() / 2;
    
   T3DPoint& point = (*iPoints)[0].iCurrent;
   TInt x = point.iX + xOffs,
        y = point.iY + yOffs;    
  
   SetPolyPoint( 0, 0, x, y );
   SetPolyPoint( 2, 0, x, y );
   SetPolyPoint( 4, 0, x, y );   
    
   point = (*iPoints)[1].iCurrent;
   x = point.iX + xOffs,
   y = point.iY + yOffs;
   SetPolyPoint( 0, 1, x, y );
   SetPolyPoint( 2, 1, x, y );
   SetPolyPoint( 5, 0, x, y );    
    
   point = (*iPoints)[2].iCurrent;
   x = point.iX + xOffs,
   y = point.iY + yOffs;
   SetPolyPoint( 0, 2, x, y );
   SetPolyPoint( 3, 0, x, y );
   SetPolyPoint( 5, 1, x, y );           
    
   point = (*iPoints)[3].iCurrent;
   x = point.iX + xOffs,
   y = point.iY + yOffs;
   SetPolyPoint( 0, 3, x, y );
   SetPolyPoint( 3, 1, x, y );
   SetPolyPoint( 4, 1, x, y );
    
   point = (*iPoints)[4].iCurrent;
   x = point.iX + xOffs,
   y = point.iY + yOffs;
   SetPolyPoint( 1, 0, x, y );
   SetPolyPoint( 2, 3, x, y );
   SetPolyPoint( 4, 3, x, y );
    
   point = (*iPoints)[5].iCurrent;
   x = point.iX + xOffs,
   y = point.iY + yOffs;
   SetPolyPoint( 1, 1, x, y );
   SetPolyPoint( 2, 2, x, y );
   SetPolyPoint( 5, 3, x, y );
        
   point = (*iPoints)[6].iCurrent;
   x = point.iX + xOffs,
   y = point.iY + yOffs;
   SetPolyPoint( 1, 2, x, y );
   SetPolyPoint( 3, 3, x, y );
   SetPolyPoint( 5, 2, x, y );
    
   point = (*iPoints)[7].iCurrent;    
   x = point.iX + xOffs,
   y = point.iY + yOffs;
   SetPolyPoint( 1, 3, x, y );
   SetPolyPoint( 3, 2, x, y );
   SetPolyPoint( 4, 2, x, y );

   // ��⠭���� �������� ��� �࠭�� 
   if( maxZ < 4 )
   {    	
      (*iPolies)[0].iVisible = ETrue;
      (*iPolies)[1].iVisible = EFalse;
   } 
   else
   {
      (*iPolies)[0].iVisible = EFalse;
      (*iPolies)[1].iVisible = ETrue;
   }

   if( maxZ < 2  || maxZ > 3 &&  maxZ < 6  )
   {
      (*iPolies)[2].iVisible = ETrue;
      (*iPolies)[3].iVisible = EFalse;
   }
   else
   {
      (*iPolies)[2].iVisible = EFalse;
      (*iPolies)[3].iVisible = ETrue;
   }
    
   if( maxZ == 0 || maxZ == 3 || maxZ == 4 || maxZ == 7 )
   {
      (*iPolies)[4].iVisible = ETrue;
      (*iPolies)[5].iVisible = EFalse;
   }
   else
   {
      (*iPolies)[4].iVisible = EFalse;
      (*iPolies)[5].iVisible = ETrue;
   }        
}

// �����饭�� ��ࠫ���������� � ��室��� ���ﭨ�
void CParallelepiped :: Reset() 
{ 
   iMatrix->Reset(); 
   SetInitPoints( iRect, iPoint ); 
}

// �� ��������� ࠧ��஢ ������ ���ᮢ�� �㦭� ��������
// ���न���� ��設 � ���ᮧ���� iOffScreenBitmap ᮣ��᭮���� ࠧ��ࠬ
void CParallelepiped :: SizeChanged( const TRect& aRect, const TPoint& aPoint )
{
   SetInitPoints( aRect, aPoint );   

   delete iOffScreenBitmapGc;
   delete iOffScreenBitmapDevice;
   delete iOffScreenBitmap;	   	   
   
   iOffScreenBitmap = new ( ELeave ) CFbsBitmap();
   iOffScreenBitmap->Create( aRect.Size(), iMode );
            
   iOffScreenBitmapDevice = CFbsBitmapDevice::NewL( iOffScreenBitmap ); 
      
   iOffScreenBitmapGc  = NULL;
   iOffScreenBitmapDevice->CreateContext( iOffScreenBitmapGc  );   
}

// ���ᮢ�� ��ࠫ���������� ᭠砫� �� iOffScreenBitmap, ��⥬ 㦥
// ��ନ஢���� iOffScreenBitmap ���ᮢ뢠���� �� ��࠭
void CParallelepiped :: Draw( CAnimGc& aGc ) const
{
   CFbsBitGc& gc = *iOffScreenBitmapGc;

   gc.SetBrushColor( KRgbWhite );
   gc.Clear( iRect );	

   // 梥� 䮭� ������ �� ⮣�, � 䮪�� �� ��ࠫ��������� ��� ���
   if( Focused() )
   {
      gc.SetPenSize( TSize( 1, 1 ) );
      gc.SetPenColor( KRgbBlack );
      gc.SetBrushColor( TRgb( 0x909050 ));
      gc.DrawRect( iRect );
   }

   // ���ᮢ�� �������஢
   DrawGauge( gc, Focused() ? iDCurrent == &iDx : EFalse, iDx, 5  );
   DrawGauge( gc, Focused() ? iDCurrent == &iDy : EFalse, iDy, 11 );
   DrawGauge( gc, Focused() ? iDCurrent == &iDz : EFalse, iDz, 17 );
   
   gc.SetPenStyle( CGraphicsContext :: ESolidPen );
   gc.SetPenColor( KRgbBlack );
   gc.SetPenSize( TSize( 2, 2 ) );
   gc.SetBrushStyle( CGraphicsContext :: ESolidBrush );      

   // ���ᮢ�� ���������
   for( TInt i = 0; i < 6; i ++ )
   {	
      TParallelepipedPoly poly = ( *iPolies )[i];
      poly.SetArray( iPoly );
      if( poly.iVisible )
      {
         gc.SetBrushColor( poly.iColor );      
         gc.DrawPolygon( iPoly, 4 );   		   
      }
   }

   // �뢮� �� ��࠭ 
   aGc.BitBlt( iPoint, iOffScreenBitmap );   
}

// ���ᮢ�� ��������
void CParallelepiped :: DrawGauge( CFbsBitGc& aGc, TBool aActive, TInt aValue, TInt aYOffset ) const
{

   aGc.SetPenSize( TSize( 1, 1 ) );
   if( aActive )
   {
      aGc.SetBrushColor( KRgbRed );
      aGc.SetPenColor( KRgbBlack );
      iGaugePoly[ 0 ] = TPoint( 5,  aYOffset - 3 );
      iGaugePoly[ 1 ] = TPoint( 10, aYOffset + 2 );
      iGaugePoly[ 2 ] = TPoint( 5,  aYOffset + 7 );
      aGc.DrawPolygon( iGaugePoly, 3 );

      aGc.SetBrushColor( KRgbGreen );
      aGc.SetPenColor( KRgbBlack );   
   }
   else
   {
      aGc.SetBrushColor( KRgbGray );
      aGc.SetPenColor( KRgbDarkGray );
   }
   for( TInt i = 0; i < aValue / 10; i++ )
      aGc.DrawRect( TRect( TPoint( 12 + i * 7, aYOffset ), TSize( 5, 5 ) ) );
}

TBool CParallelepiped :: Focused() const 
{ 
   return iFocused; 
}

